日本からの BlockedRequests が増えた時に CloudWatch でアラートする
こんにちは!クラウド事業本部コンサルティング部のたかくに(@takakuni_)です。
みなさん、AWS WAF 使ってますでしょうか。
あらかじめ Count アクションで運用し、誤検知が起こらないかを静観した後に Block アクションに切り替えていく運用をされている方も多いと思います。
Count モードで問題ないことを確認しつつも、アプリケーションの動作変更や WAF バージョンのアップグレードなどシステムの変化によって、Block 後の誤検知が発生しないか心配な方もいらっしゃるのではないかと思います。もちろん、バージョンアップの際はテスト環境で入念にテストを行っていただくのが大前提ですが、その後の監視も重要です。
そこで今回は誤検知に素早く気がつけるよう、AWS WAF の BlockedRequests メトリクスをトリガーに CloudWatch アラームを設定したいと思います。
BlockedRequests
BlockedRequests は AWS WAF で発行されるメトリクスの 1 つで、名前の通りブロックされたウェブリクエストの数を指します。
ブロックされたウェブリクエストの数。
レポート条件: ゼロ以外の値がある。
有効な統計: Sum
この、BlockedRequests のみの観点でアラートを飛ばすと、閾値によってはオオカミ少年になりかねないため、今回は日本の利用者が多いシステムを想定し「日本からの BlockedRequests」を監視対象としてみます。
ディメンションの利用
監視対象が「日本からの BlockedRequests」と決まったところで、日本からの
はどうやって判断しましょう。
AWS WAF のメトリクスには多種多様なディメンションが用意されており、今回は要件に満たすかつ、シンプルな Country
ディメンションを利用することにしました。
リクエストの送信元の国 これは、国際標準化機構 (ISO) 3166 規格の 2 文字の名称です。たとえば、米国は US、ウクライナは UA です。
リクエストに X-Forwarded-For ヘッダーがある場合、AWS WAF はそのヘッダーを使用してこの設定を決定します。それ以外の場合は、AWS WAF はクライアント IP の国を使用します。この判定は、ルールで原産国を決定するために使用するロジックとは無関係です。AWS WAF は MaxMind GeoIP データベースを使用して IP の場所を決定します。
やってみる
それでは実際にやってみます。
ALB + ECS の Web アプリケーションに AWS WAF をアタッチします。AWS WAF のメトリクスに閾値を設け CloudWatch アラームを設定し、SNS へ通知します。
なお、AWS WAF, ALB, ECS に関しては構築済みとします。
ちなみに AWS WAF は、以下のルールをワンクリック統合で作成しました。
- AWS-AWSManagedRulesAmazonIpReputationList
- AWS-AWSManagedRulesCommonRuleSet
- AWS-AWSManagedRulesKnownBadInputsRuleSet
SNS
通知用に SNS トピックを作成します。
今回、サブスクリプションには E メールを選択しました。
CloudWatch アラーム
CloudWatch アラームの作成を行います。
マネジメントコンソールの場合、発行されたメトリクスのみ、アラートを上げるメトリクスに選択できます。つまり、実際に日本でブロックされないと、アラートの作成ができません。
そのため今回は Terraform で作成しました。閾値は 3 分内の 3 データポイント(≒ 3 分間連続)で、1 分間に合計 3 回以上日本でブロックされた時に通知を飛ばしてみます。
resource "aws_cloudwatch_metric_alarm" "this" {
alarm_name = "aws-waf-jp-block"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = 3
datapoints_to_alarm = 3
metric_name = "BlockedRequests"
namespace = "AWS/WAFV2"
period = 60
statistic = "Sum"
threshold = 3
alarm_description = "This metric monitors blocked jp requests"
treat_missing_data = "notBreaching"
insufficient_data_actions = []
dimensions = {
Country = "JP"
WebACL = "CreatedByALB-aws-waf" # 適宜変更
Region = "ap-northeast-1" # 適宜変更
}
alarm_actions = [
var.sns_topic_arn
]
}
バージニアリージョンの CloudShell で実行してみました。悪意のあるリクエストを送ると、AWS WAF でブロックされていますね。
data コマンドで表示していた時刻には、メトリクスが発行されていないことがわかりますね。JP で絞っているため想定通りです。
続いて東京リージョンです。こちらもうまく繋がっていますね。
閾値に到達するよう while でブロックされるリクエストをループさせます。
while true; do TZ=Asia/Tokyo date && curl http://aws-waf-123456789.ap-northeast-1.elb.amazonaws.com/{悪意のあるリクエスト} && TZ=Asia/Tokyo date; sleep 10; done
想定通りメトリクスが発行され、閾値を超えてきました。
アラーム状態に遷移しました。想定通りです。
以下の内容でメールも飛んできています。やりたかったことが実現できました。
まとめ
以上、「日本からの BlockedRequests が増えた時に CloudWatch でアラートする」でした。
誤検知がないかを監視する手段の 1 つとして参考になれば幸いです。
クラウド事業本部コンサルティング部のたかくに(@takakuni_)でした!